package com.legsem.jhosync.change;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;

import com.legsem.jhosync.util.KAVUtil;

/**
 * A set of changes that needs to be sent back to the client.
 * <p/>
 * This is a wrapper on Map that associates primary keys to sets of
 * column/values.
 * 
 */
public abstract class Changes {

    Map < String, Map < String, Object >> changes;

    /**
     * Default CTOR.
     */
    public Changes() {

    }

    /**
     * CTOR from existing map.
     * 
     * @param changes the changes map
     */
    public Changes(Map < String, Map < String, Object >> changes) {
        this.changes = changes;
    }

    /**
     * CTOR from an encoded set of changes.
     * 
     * @param encoded the encoded changes.
     */
    public Changes(String encoded) {
        this.changes = KAVUtil.decode(encoded);
    }

    public Map < String, Map < String, Object >> get() {
        return get(false);
    }

    public Map < String, Map < String, Object >> get(boolean create) {
        if (create == true && changes == null) {
            changes = new HashMap < String, Map < String, Object >>();
        }
        return changes;
    }

    /**
     * Sets the changes from a map.
     * 
     * @param changes the map changes
     */
    public void set(Map < String, Map < String, Object >> changes) {
        this.changes = changes;
    }

    /**
     * Sets the changes from en encoded string.
     * 
     * @param changes the map changes
     */
    public void set(String encoded) {
        this.changes = KAVUtil.decode(encoded);
    }

    public void put(String key, Map < String, Object > value) {
        get(true).put(key, value);
    }

    public boolean empty() {
        return (changes == null || changes.size() == 0);
    }

    public int size() {
        if (changes != null) {
            return changes.size();
        } else {
            return 0;
        }
    }

    /**
     * Encodes these changes in a string.
     * 
     * @return an encoded string
     */
    public String encode() {
        return KAVUtil.encode(changes);
    }

    /**
     * The sorting that takes place here is necessary so that maps always
     * display in the same order (much easier for test cases).
     * 
     * @return an stringized content
     */
    @Override
    public String toString() {
        if (changes == null) {
            return null;
        }
        Map < String, Map < String, Object >> sorted = new TreeMap < String, Map < String, Object >>();
        for (Entry < String, Map < String, Object >> entry : changes.entrySet()) {
            sorted.put(entry.getKey(),
                    new TreeMap < String, Object >(entry.getValue()));
        }
        return sorted.toString();
    }

}
